home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
utils
/
ctv201.arc
/
CTV201.C
< prev
Wrap
C/C++ Source or Header
|
1988-03-22
|
20KB
|
865 lines
/*
* CT: A file-copying program that maintains time-stamps on the
* destination file(s).
*
* AUTHOR: Jonathan Fischer, August 1987 (original)
* (see #define VERSION for latest version)
*
* USAGE: ct [-bmnrv] <file1> <file2>
* or ct [-bmnrv] <file1> ... <directory>
* where
* -b: Backup: only copy files newer than the destination files.
* -m: Conserve memory; for MT C-Shell usage.
* -n: No information is to be printed.
* -r: Recursively copy directories and their contents.
* -v: Request user verification when destination file exists.
*
* NOTE: CT now expands wildcards, so it may be called with wildcards
* from the desktop.
*
* CT may require some hacking to compile under anything but
* Mark Williams C.
*/
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <osbind.h>
#define VERSION "Version 2.01, Mar. 22, 1988\r\n"
#define YES 1
#define NO 0
#define MAXBUFSIZE 500000 /* For Mega machines, make this as big as */
/* you like. This is typically the most */
/* I'd have free on my ST. */
#define MEMRESERVE 50000 /* Approximate amount of memory that should */
/* be reserved for mallocing. */
#define SMALLBUFSIZE (40000 + MEMRESERVE)
/*
* Variables used by the wildcard routines:
* argv gets expanded (if wildcards exist) into newargv.
*/
#define ARGCLIMIT 2000
#define ARGCLIMITSTR "2000"
int newargc;
char *newargv[ARGCLIMIT];/* Allow for (hopefully) much more than */
/* enough space. */
typedef struct datimbuf {
unsigned int seconds:5;
unsigned int minutes:6;
unsigned int hours:5;
unsigned int day:5;
unsigned int month:4;
unsigned int year:7;
} DATIMBUF;
typedef struct {
char reserved[21];
char attribute;
DATIMBUF datime;
int losize, hisize;
char fname[14];
} DTABUF;
char *malloc(), *lmalloc(), *rindex(), *strcat(), *strcpy(),
*LowerStr();
void Usage(), Error(), Msg(), GoAway(), Files2Dir(), File2File(),
FindWildcards(), ExpandWildcards(), CopyDir(), ReadRoot();
DATIMBUF finfo;
DTABUF dta;
long _stksize = 15000L; /* Override default 2K stack. */
unsigned long bufsize;
int firstarg; /* First argument (after options). */
int ch; /* Character read from keyboard. */
char *buf; /* I/O buffer. */
char *prgname; /* Program name for error messages. */
char tempbuf[256];
char FromDesktop,
info, verify, recurse, memconserve, backup; /* Flags */
int
main(argc, argv)
int argc;
char **argv;
{
register int loop;
/*
* Most shells pass the program name in argv[0]. But if argv[0] is
* empty, then set the program name to "ct."
*/
if (*(prgname = argv[0]) == 0) {
prgname = "ct";
/* Assume that ct is being run from the desktop. */
FromDesktop = YES;
} /* if */
else
FromDesktop = NO;
if (argc < 3) {
Usage();
} /* if one or no params */
/*
* Set GEMDOS' dta buffer.
*/
Fsetdta(&dta);
FindWildcards(&argc, &argv);
/* Get any command line options (e.g., "-v"). */
backup = NO;
memconserve = NO;
info = YES;
recurse = NO;
verify = NO;
if (argv[1][0] == '-') {
firstarg = 2;
for (loop = YES; argv[1][loop]; ++loop) {
switch (argv[1][loop]) {
case 'b':
backup = YES;
break;
case 'm':
memconserve = YES;
break;
case 'n':
info = NO;
break;
case 'r':
recurse = YES;
break;
case 'v':
verify = YES;
break;
default:
Usage();
} /* switch */
} /* for */
} /* if */
else
firstarg = 1;
/* Check for only one file parameter. */
if (argc - firstarg == 1)
Usage();
/*
* If memconserve:
* Allocate a maximum of SMALLBUFSIZE bytes.
*
* else:
* Allocate the largest buffer possible.
*/
bufsize = memconserve ? SMALLBUFSIZE : MAXBUFSIZE;
while (((buf = lmalloc(bufsize)) == NULL) &&
(bufsize -= 2000) > 0)
;
if (buf == NULL)
Error("Out of memory.", NULL);
/*
* Now free the buffer and reallocate one of a size which leaves enough
* room for all the mallocs later in the program. NOTE: this all could
* have been done with a Malloc(-1L), but mixing Malloc and malloc seems
* to be a definite no-no, and I prefer to use malloc over Malloc.
*/
free(buf);
buf = lmalloc(bufsize -= MEMRESERVE);
/*
* Format I:
* Backup one or more files to a destination directory.
*/
if (IsDir(argv[argc-1]))
Files2Dir(argc, argv);
/*
* Format II:
* Copy one file to another.
*/
else if (argc - firstarg == 2)
File2File(argv[firstarg], argv[firstarg+1]);
else
Error(argv[argc-1], " is not a directory.");
GoAway(0);
} /* main() */
void
Usage()
{
Cconws("Usage:\t");
Cconws(prgname);
Cconws(" [-bmnrv] <file1> <file2>\r\n\t");
Cconws(prgname);
Cconws(" [-bmnrv] <file> ... <directory>\r\n\n\
\t-b: Backup: only copy files newer than the destination files.\r\n\
\t-m: Conserve memory (for MT C-Shell).\r\n");
Cconws("\t-n: No information is to be printed.\r\n\
\t-r: Recursively copy directories and their contents.\r\n\
\t-v: Request user verification when destination file exists.\r\n");
Cconws(VERSION);
GoAway(1);
} /* Usage() */
void
Error(string1, string2)
char *string1, *string2;
{
Cconws(prgname);
Cconws(":\t");
Cconws(string1);
if (string2 != NULL)
Cconws(string2);
Cconws("\r\n");
GoAway(1);
} /* Error() */
void
Msg(string1, string2)
char *string1, *string2;
{
Cconws(prgname);
Cconws(":\t");
Cconws(string1);
if (string2 != NULL)
Cconws(string2);
Cconws("\r\n");
} /* Msg() */
void
GoAway(code)
int code;
{
if (FromDesktop) {
Cconws("\r\nHit any key to return to desktop...");
Cnecin();
Cconws("\033f");
} /* if */
exit(code);
} /* GoAway() */
void
File2File(source, dest)
char *source, *dest;
{
unsigned long rcount;
char retry_open;
int sfile, dfile;
retry_open = YES;
/* Open the files. */
retry:
if ((sfile = Fopen(source, 0)) < 0) {
if (IsDir(source)) {
if (recurse) {
CopyDir(source, dest);
return;
} /* if */
else {
Msg(source, " is a directory.");
return;
} /* else */
} /* if */
/*
* If a disk has been swapped, GEMDOS doesn't know about any
* files contained in subdirectories. So in case this is the problem,
* get GEMDOS to read the root directory of the disk in question.
* Then it will know about subdirectories on the new disk.
*/
else if (retry_open) {
retry_open = NO; /* Only want to retry once. */
ReadRoot(source);
goto retry;
} /* if */
Msg("Can't open ", source);
return;
} /* if can't open file. */
/*
* If "-b" is specified, check if the file exists, and if it does
* then only copy over it if the source file is more recent.
*
* If the "-v" option has been specified, then first check if
* the destination file already exists. If so, query whether
* or not to replace it.
*/
if ((verify || backup) && Fsfirst(dest, 0x23) == 0) {
if (backup) {
/* Store the destination timestamp in 'finfo.' */
finfo = dta.datime; /* Structure assignment. */
Fsfirst(source, 0x23); /* Get info for source file. */
/*
* Compare timestamps of source and dest. If the source isn't
* more recent than the dest, then return.
*/
if (!MoreRecent(dta.datime, finfo))
return;
} /* if */
if (verify)
while (1) {
Cconws("Replace file \"");
Cconws(dest);
Cconws("\"? (Yes/No/All) ");
ch = tolower((int)Cnecin());
Cconws("\r\033K");
if (ch == 'y')
break;
if (ch == 'n')
return;
if (ch == 'a') {
verify = NO;
break;
} /* if */
} /* while and if*/
} /* if */
/* Open the destination file. */
if ((dfile = Fcreate(dest, 0)) < 0) {
Fclose(sfile);
if (IsDir(dest)) {
Msg(dest, " exists and is a directory.");